﻿/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Windows Forms Controls Class Library
 * Version 2.00
 * 
 * File Browse Button Class
 *      A button control for invoking the Open- and Save- File common dialogs.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Text;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Timers;

namespace Adaptive.Foundation.Windows.Forms
{
    /// <summary>
    ///  A button control for invoking the Open- and Save- File common dialogs.
    /// </summary>
    public partial class FileBrowseButton : Button
    {
        /*--------------------------------------------------------------------------------------
         * Public Events
         *------------------------------------------------------------------------------------*/
        #region Public Events
        /// <summary>
        /// Occurs just before the common dialog is displayed.
        /// </summary>
        public event EventHandler BeforeDialogDisplay;
        /// <summary>
        /// Occurs when the user cancels the operation.
        /// </summary>
        public event EventHandler UserCancelled;
        /// <summary>
        /// Occurs when the user presses OK on the common dialog.
        /// </summary>
        public event EventHandler OperationSuccess;
        #endregion

        /*--------------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// Last result of common dialog operation.
        /// </summary>
        private DialogResult _lastDialogResult = DialogResult.Cancel;
        /// <summary>
        /// Indicates which dialog to display.
        /// </summary>
        private FileBrowseStyle _browseStyle = FileBrowseStyle.OpenFileDialog;
        /// <summary>
        /// Add extension flag.
        /// </summary>
        private bool _addExtension = true;
        /// <summary>
        /// Auto-size flag.
        /// </summary>
        private bool _autoSize;
        /// <summary>
        /// Multi-select flag.
        /// </summary>
        private bool _multiSelect;
        /// <summary>
        /// Show read-only check flag.
        /// </summary>
        private bool _showReadOnly;
        /// <summary>
        /// Show help flag.
        /// </summary>
        private bool _showHelp;
        /// <summary>
        /// Read-only checked flag.
        /// </summary>
        private bool _readOnlyChecked;
        /// <summary>
        /// Filter.
        /// </summary>
        private string _filter = string.Empty;
        /// <summary>
        /// Default extension.
        /// </summary>
        private string _defaultExtension = string.Empty;
        /// <summary>
        /// Initial directory string.
        /// </summary>
        private string _initialDirectory = string.Empty;
        /// <summary>
        /// Title string.
        /// </summary>
        private string _title = string.Empty;
        /// <summary>
        /// File name list.
        /// </summary>
        private List<string> _fileNames;
        /// <summary>
        /// File name.
        /// </summary>
        private string _fileName = string.Empty;

        #endregion

        /*--------------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public FileBrowseButton()
            : base()
        {
            InitializeComponent();
        }
        #endregion

        /*--------------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets a value indicating whether the button is to be automatically sized.
        /// </summary>
        /// <value>
        /// <b>true</b> to automatically size the control; otherwise, <b>false</b>.
        /// </value>
        [Browsable(true), Category("Appearance"), Description("Allows automatic sizing based on text content."), DefaultValue(false)]
        public override bool AutoSize
        {
            get { return _autoSize; }
            set
            {
                _autoSize = value;
                Invalidate();
            }
        }
        /// <summary>
        /// Gets the last result of common dialog operation.
        /// </summary>
        /// <value>
        ///  A <see cref="DialogResult"/> enumerated value indicating the last action.
        /// </value>
        [Browsable(false)]
        public DialogResult LastDialogResult
        {
            get
            {
                return _lastDialogResult;
            }
        }
        /// <summary>
        /// Gets or sets a value indicating which dialog to display.
        /// </summary>
        /// <value>
        /// A <see cref="FileBrowseStyle"/> enumerated value.
        /// </value>
        [Browsable(true), DefaultValue(0), Description("The type of dialog to display.")]
        public FileBrowseStyle BrowseStyle
        {
            get
            {
                return _browseStyle;
            }
            set
            {
                _browseStyle = value;
                Invalidate();
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether a file dialog automatically adds an extension to a 
        /// filename if the user omits an extension.
        /// </summary>
        /// <value>
        /// <b>true</b> if extensions are added; otherwise, <b>false</b>. The default is <b>true</b>.
        /// </value>
        [Browsable(true), DefaultValue(true), Description("Automatically add the default extension when omitted.")]
        public bool AddExtension
        {
            get
            {
                return _addExtension;
            }
            set
            {
                _addExtension = value;
            }
        }
        /// <summary>
        /// Gets or sets an option indicating whether OpenFileDialog allows users to select multiple files.
        /// </summary>
        /// <value>
        /// <b>true</b> if  if multiple selections are allowed; otherwise, <b>false</b>. The default is <b>false</b>.
        /// </value>
        [Browsable(true), DefaultValue(false), Description("Allow or disallow multiple selections when opening files.")]
        public bool MultiSelect
        {
            get
            {
                return _multiSelect;
            }
            set
            {
                _multiSelect = value;
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether OpenFileDialog contains a read-only check box.
        /// </summary>
        /// <value>
        /// <b>true</b> if the read-only check box is shown; otherwise, <b>false</b>. The default is <b>false</b>.
        /// </value>
        [Browsable(true), DefaultValue(false), Description("Show or hide the read-only check box on the Open file dialog.")]
        public bool ShowReadOnly
        {
            get
            {
                return _showReadOnly;
            }
            set
            {
                _showReadOnly = value;
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether a help indicator is shown.
        /// </summary>
        /// <value>
        /// <b>true</b> if the help indicator is shown; otherwise, <b>false</b>. The default is <b>false</b>.
        /// </value>
        [Browsable(true), DefaultValue(false), Description("Show or hide the help indicator the common dialogs.")]
        public bool ShowHelp
        {
            get
            {
                return _showHelp;
            }
            set
            {
                _showHelp = value;
            }
        }
        /// <summary>
        ///Gets or sets a value indicating whether the read-only check box displayed by OpenFileDialog is selected.
        /// </summary>
        /// <value>
        /// <b>true</b> if the checkbox is selected; otherwise, <b>false</b>. The default is <b>false</b>.
        /// </value>
        [Browsable(true), DefaultValue(false), Description("Select or de-select the read-only check box if shown.")]
        public bool ReadOnlyChecked
        {
            get
            {
                return _readOnlyChecked;
            }
            set
            {
                _readOnlyChecked = value;
            }
        }
        /// <summary>
        /// Gets or sets the filter string that determines what types of files are displayed from either the 
        /// <see cref="OpenFileDialog"/> or <see cref="SaveFileDialog"/>.
        /// </summary>
        /// <value>
        /// A String that contains the filter. The default is Empty, which means that no filter is applied and all 
        /// file types are displayed.
        /// </value>
        [Browsable(true), DefaultValue(""), Description("Indicates the filter for file types in the dialog.")]
        public string Filter
        {
            get
            {
                return _filter;
            }
            set
            {
                _filter = value;
            }
        }
        /// <summary>
        /// Gets or sets a value that specifies the default extension string to use to filter the list of files 
        /// that are displayed.
        /// </summary>
        /// <value>
        /// The default extension string. The default is Empty.
        /// </value>
        [Browsable(true), DefaultValue(""), Description("The default extension value.")]
        public string DefaultExtension
        {
            get
            {
                return _defaultExtension;
            }
            set
            {
                _defaultExtension = value;
            }
        }
        /// <summary>
        /// Gets or sets the initial directory that is displayed by a file dialog.
        /// </summary>
        /// <value>
        /// A String that contains the initial directory. The default is Empty.
        /// </value>
        [Browsable(true), DefaultValue(""), Description("The starting directory path.")]
        public string InitialDirectory
        {
            get
            {
                return _initialDirectory;
            }
            set
            {
                _initialDirectory = value;
            }
        }
        /// <summary>
        /// Gets or sets the text that appears in the title bar of a file dialog.
        /// </summary>
        /// <value>
        /// A String that is the text that appears in the title bar of a file dialog. The default is Empty.
        /// </value>
        [Browsable(true), DefaultValue(""), Description("The title to display on the dialog.")]
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                _title = value;
            }
        }
        /// <summary>
        /// Gets the reference to the list of file names selected in the dialog.
        /// </summary>
        /// <value>
        /// A <see cref="List"/> instance containing the selected file name list.
        /// </value>
        [Browsable(false)]
        public List<string> FileNames
        {
            get
            {
                return _fileNames;
            }
        }
        /// <summary>
        /// Gets or sets a string containing the full path of the file selected in a file dialog.
        /// </summary>
        /// <value>
        /// A String that is the full path of the file selected in the file dialog. The default is Empty.
        /// </value>
        [Browsable(true), DefaultValue(""), Description("Selected file name value.")]
        public string FileName
        {
            get
            {
                return _fileName;
            }
            set
            {
                _fileName = value;
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------------
         * Protected Method Overrides
         *------------------------------------------------------------------------------------*/
        #region Protected Method Overrides
        /// <summary>
        /// Raises the <see cref="E:Click"/> event and displays the specified dialog.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected override void OnClick(EventArgs e)
        {
            //Call base event.
            base.OnClick(e);

            OnBeforeDialogDisplay(EventArgs.Empty);

            if (_browseStyle == FileBrowseStyle.OpenFileDialog)
                ShowOpenFileDialog();
            else
                ShowSaveFileDialog();
        }
        #endregion

        /*--------------------------------------------------------------------------------------
         * Protected Event Methods
         *------------------------------------------------------------------------------------*/
        #region Protected Event Methods
        /// <summary>
        /// Raises the <see cref="E:Paint"/> event and auto-sizes the button.
        /// </summary>
        /// <param name="e">
        /// A <see cref="PaintEventArgs"/> event argument instance containing the 
        /// <see cref="Graphics"/> object used for drawing.
        /// </param>
        protected override void OnPaint(PaintEventArgs e)
        {
            SizeF textSize;

            //Re-set width based on text size.
            if (_autoSize)
            {
                textSize = e.Graphics.MeasureString(Text, Font);
                Width = Convert.ToInt32(textSize.Width) + 15;
            }

            base.OnPaint(e);
        }
        /// <summary>
        /// Raises the <see cref="BeforeDialogDisplay"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnBeforeDialogDisplay(EventArgs e)
        {
            if (BeforeDialogDisplay != null)
                BeforeDialogDisplay(this, e);
        }
        /// <summary>
        /// Raises the <see cref="UserCancelled"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnUserCancelled(EventArgs e)
        {
            if (UserCancelled != null)
                UserCancelled(this, e);
        }
        /// <summary>
        /// Raises the <see cref="OperationSuccess"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="EventArgs"/> event arguments instance.
        /// </param>
        protected virtual void OnOperationSuccess(EventArgs e)
        {
            if (OperationSuccess != null)
                OperationSuccess(this, e);
        }
        #endregion

        /*--------------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        #endregion

        /*--------------------------------------------------------------------------------------
         * Private Event Handlers
         *------------------------------------------------------------------------------------*/
        #region Private Event Handlers
        #endregion

        /*--------------------------------------------------------------------------------------
         * Private Methods / Functions
         *------------------------------------------------------------------------------------*/
        #region Private Methods / Functions
        /// <summary>
        /// Displays the Open File dialog.
        /// </summary>
        private void ShowOpenFileDialog()
        {
            OpenFileDialog dialog = null;                       //Dialog to be displayed.
            DialogResult result = DialogResult.Cancel;          //Result of dialog interaction.

            //Create and configure the dialog.
            dialog = new OpenFileDialog();
            dialog.AddExtension = _addExtension;
            dialog.AutoUpgradeEnabled = true;
            dialog.CheckFileExists = true;
            dialog.CheckPathExists = true;
            dialog.DefaultExt = _defaultExtension;
            dialog.FileName = _fileName;
            dialog.Filter = _filter;
            dialog.InitialDirectory = _initialDirectory;
            dialog.Multiselect = _multiSelect;
            dialog.ReadOnlyChecked = _readOnlyChecked;
            dialog.ShowHelp = _showHelp;
            dialog.ShowReadOnly = _showReadOnly;
            dialog.SupportMultiDottedExtensions = true;
            dialog.Title = _title;
            dialog.ValidateNames = true;

            result = dialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                //Clear last results.
                if (_fileNames != null)
                    _fileNames.Clear();
                else
                    _fileNames = new List<string>();
                _fileName = string.Empty;
                _lastDialogResult = result;

                //Save result.
                if (dialog.Multiselect)
                    _fileNames.AddRange(dialog.FileNames);
                else
                    _fileName = dialog.FileName;

                OnOperationSuccess(EventArgs.Empty);
            }
            else
            {
                OnUserCancelled(EventArgs.Empty);
            }
            dialog.Dispose();
            dialog = null;
        }
        /// <summary>
        /// Displays the Save File dialog.
        /// </summary>
        private void ShowSaveFileDialog()
        {
            SaveFileDialog dialog = null;                       //Dialog to be displayed.
            DialogResult result = DialogResult.Cancel;          //Result of dialog interaction.

            //Create and configure the dialog.
            dialog = new SaveFileDialog();
            dialog.AddExtension = _addExtension;
            dialog.AutoUpgradeEnabled = true;
            dialog.CheckFileExists = false;
            dialog.CheckPathExists = true;
            dialog.DefaultExt = _defaultExtension;
            dialog.FileName = _fileName;
            dialog.Filter = _filter;
            dialog.InitialDirectory = _initialDirectory;
            dialog.ShowHelp = _showHelp;
            dialog.SupportMultiDottedExtensions = true;
            dialog.Title = _title;
            dialog.ValidateNames = true;

            result = dialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                //Clear last results.
                _fileName = string.Empty;
                _lastDialogResult = result;

                //Save result.
                _fileName = dialog.FileName;

                OnOperationSuccess(EventArgs.Empty);
            }
            else
            {
                OnUserCancelled(EventArgs.Empty);
            }
            dialog.Dispose();
            dialog = null;
        }

        #endregion
    }
}
